package com.diy.sigmund.diycommon.spring.config.dynamicthreadpool;

import java.util.List;
import java.util.Optional;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.tomcat.util.net.AbstractEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 线程池监控类
 * Tomcat线程池监控及线程池原理分析
 *
 * @author ylm-sigmund
 * @see AbstractEndpoint#createExecutor()
 * @since 2023/1/29 22:30
 */
public class ThreadPoolMonitor extends ThreadPoolExecutor {

    private static final Logger log = LoggerFactory.getLogger(ThreadPoolMonitor.class);

    /**
     * 默认拒绝策略
     */
    private static final RejectedExecutionHandler DEFAULT_HANDLER = new AbortPolicy();

    /**
     * 线程池名称，一般以业务名称命名，方便区分
     */
    private final String poolName;

    /**
     * 最短执行时间
     */
    private Long minCostTime;

    /**
     * 最长执行时间
     */
    private Long maxCostTime;
    /**
     * 总的耗时
     */
    private final AtomicLong totalCostTime = new AtomicLong();

    private final ThreadLocal<Long> startTimeThreadLocal = new ThreadLocal<>();

    // /**
    //  * 所有线程都会委托给这个execute方法，在这个方法中我们把父线程的MDC内容赋值给子线程
    //  * https://logback.qos.ch/manual/mdc.html#managedThreads
    //  *
    //  * @param command {@link Runnable}
    //  */
    // @Override
    // public void execute(@NotNull Runnable command) {
    //     // 获取父线程MDC中的内容，必须在run方法之前，否则等异步线程执行的时候有可能MDC里面的值已经被清空了，这个时候就会返回null
    //     Map<String, String> context = MDC.getCopyOfContextMap();
    //     CustomUser customUser = ContextHolder.getInstance().getCustomUser();
    //     super.execute(() -> run(command, context, customUser));
    // }
    //
    // /**
    //  * 子线程委托的执行方法
    //  *
    //  * @param command      {@link Runnable}
    //  * @param contextArray 父线程MDC内容
    //  */
    // private void run(Runnable command, Object... contextArray) {
    //     // 将父线程的MDC内容传给子线程
    //     MDC.setContextMap((Map<String, String>) contextArray[0]);
    //     ContextHolder.getInstance().setCustomUser((CustomUser) contextArray[1]);
    //     try {
    //         // 执行异步操作
    //         command.run();
    //     } finally {
    //         // 清空MDC内容
    //         MDC.clear();
    //         ContextHolder.getInstance().remove();
    //     }
    // }

    // @Override
    // public <T> Future<T> submit(Callable<T> task) {
    //     // 获取父线程MDC中的内容，必须在run方法之前，否则等异步线程执行的时候有可能MDC里面的值已经被清空了，这个时候就会返回null
    //     Map<String, String> context = MDC.getCopyOfContextMap();
    //     CustomUser customUser = ContextHolder.getInstance().getCustomUser();
    //     return super.submit(() -> call(task, context, customUser));
    // }
    //
    // private <T> T call(Callable<T> task, Object... contextArray) throws Exception {
    //     // 将父线程的MDC内容传给子线程
    //     MDC.setContextMap((Map<String, String>) contextArray[0]);
    //     ContextHolder.getInstance().setCustomUser((CustomUser) contextArray[1]);
    //     try {
    //         // 执行异步操作
    //         return task.call();
    //     } finally {
    //         // 清空MDC内容
    //         MDC.clear();
    //         ContextHolder.getInstance().remove();
    //     }
    // }

    /**
     * 调用父类的构造方法，并初始化HashMap和线程池名称
     *
     * @param corePoolSize    线程池核心线程数
     * @param maximumPoolSize 线程池最大线程数
     * @param keepAliveTime   线程的最大空闲时间
     * @param unit            空闲时间的单位
     * @param workQueue       保存被提交任务的队列
     * @param poolName        线程池名称
     */
    public ThreadPoolMonitor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
            TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler, String poolName) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                new MonitorThreadFactory(poolName), handler, poolName);
        // Executors.defaultThreadFactory(), handler, poolName);
    }


    /**
     * 调用父类的构造方法，并初始化HashMap和线程池名称
     *
     * @param corePoolSize    线程池核心线程数
     * @param maximumPoolSize 线程池最大线程数
     * @param keepAliveTime   线程的最大空闲时间
     * @param unit            空闲时间的单位
     * @param workQueue       保存被提交任务的队列
     * @param threadFactory   线程工厂
     * @param poolName        线程池名称
     */
    public ThreadPoolMonitor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
            TimeUnit unit, BlockingQueue<Runnable> workQueue,
            ThreadFactory threadFactory, String poolName) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), DEFAULT_HANDLER);
        this.poolName = poolName;
    }


    /**
     * 调用父类的构造方法，并初始化HashMap和线程池名称
     *
     * @param corePoolSize    线程池核心线程数
     * @param maximumPoolSize 线程池最大线程数
     * @param keepAliveTime   线程的最大空闲时间
     * @param unit            空闲时间的单位
     * @param workQueue       保存被提交任务的队列
     * @param threadFactory   线程工厂
     * @param handler         拒绝策略
     * @param poolName        线程池名称
     */
    public ThreadPoolMonitor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
            TimeUnit unit, BlockingQueue<Runnable> workQueue,
            ThreadFactory threadFactory, RejectedExecutionHandler handler, String poolName) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
        this.poolName = poolName;
    }

    /**
     * 线程池延迟关闭时（等待线程池里的任务都执行完毕），统计线程池情况
     */
    @Override
    public void shutdown() {
        // 统计已执行任务、正在执行任务、未执行任务数量
        log.info("{} 关闭线程池， 已执行任务: {}, 正在执行任务: {}, 未执行任务数量: {}",
                this.poolName, this.getCompletedTaskCount(), this.getActiveCount(), this.getQueue().size());
        super.shutdown();
    }

    /**
     * 线程池立即关闭时，统计线程池情况
     */
    @Override
    public List<Runnable> shutdownNow() {
        // 统计已执行任务、正在执行任务、未执行任务数量
        log.info("{} 立即关闭线程池，已执行任务: {}, 正在执行任务: {}, 未执行任务数量: {}",
                this.poolName, this.getCompletedTaskCount(), this.getActiveCount(), this.getQueue().size());
        return super.shutdownNow();
    }

    /**
     * 任务执行之前，记录任务开始时间
     */
    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        startTimeThreadLocal.set(System.currentTimeMillis());
    }

    /**
     * 任务执行之后，计算任务结束时间
     */
    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        long costTime = System.currentTimeMillis() - startTimeThreadLocal.get();
        startTimeThreadLocal.remove();
        maxCostTime = Optional.ofNullable(maxCostTime).orElse(0L);
        maxCostTime = maxCostTime > costTime ? maxCostTime : costTime;
        if (getCompletedTaskCount() == 0) {
            minCostTime = costTime;
        }
        minCostTime = minCostTime < costTime ? minCostTime : costTime;
        totalCostTime.addAndGet(costTime);
        log.info("{}-pool-monitor: " +
                        "任务耗时: {} ms, 初始线程数: {}, 核心线程数: {}, 执行的任务数量: {}, " +
                        "已完成任务数量: {}, 任务总数: {}, 队列里缓存的任务数量: {}, 池中存在的最大线程数: {}, " +
                        "最大允许的线程数: {},  线程空闲时间: {}, 线程池是否关闭: {}, 线程池是否终止: {}",
                this.poolName,
                costTime, this.getPoolSize(), this.getCorePoolSize(), this.getActiveCount(),
                this.getCompletedTaskCount(), this.getTaskCount(), this.getQueue().size(), this.getLargestPoolSize(),
                this.getMaximumPoolSize(), this.getKeepAliveTime(TimeUnit.MILLISECONDS), this.isShutdown(), this.isTerminated());
    }


    public Long getMinCostTime() {
        return minCostTime;
    }

    public Long getMaxCostTime() {
        return maxCostTime;
    }

    public long getAverageCostTime() {
        if (getCompletedTaskCount() == 0 || totalCostTime.get() == 0) {
            return 0;
        }
        return totalCostTime.get() / getCompletedTaskCount();
    }

}

